;(function(global,factory){
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory()
        : typeof define === 'function' && define.amd ? define(['jquery'],factory)
        : global.layui && layui.define ? layui.define(['jquery'],function (exports){let $ = layui.jquery;exports('hzCalendar',factory($));})
            : global.hzCalendar = factory($);
})(this,function($){
    let dftOpts = {
        ele:'#hzCalendar'
        ,checkTimes:[]
        ,calTags:['日','一','二','三','四','五','六']
        ,shade:true
        ,shadeClose:true
        ,scrollbar:false
        ,events:{
            renderBefore(){

            }
            ,rendered(){

            }
            ,toggleBefore(){

            }
            ,checkBefore:function(){

            }
        }
        ,isVisible:false
    }
        ,curDate = new Date()

    let CheckCalendar = function(options){
        this.setting = $.extend(true,{},dftOpts,options);
        this.curDate = curDate;
        this.showDate = new Date();
        this.ele = CheckCalendar.utils.getEl(this.setting.ele);
        this.calData = null;
        this.isRender = false;
        this.ready();
    };

    CheckCalendar.utils={
        getEl:function(el){
            return el.nodeType == Node.ELEMENT_NODE ? el : document.querySelector(el);
        }
        ,headWordToUpCase(str){
            return str.toLowerCase().replace(/\b(\w)|\s(\w)/g,function(word){return word.toUpperCase()})
        }
        ,isType:function(type){
            return (obj)=>{
                type = CheckCalendar.utils.headWordToUpCase(type);
                return Object.prototype.toString.call(obj) == '[object '+type+']';
            }
        }
        //动画结束后的回调
        ,animationEnd:function(ele,sucHandle,errHandle){
            //1、获取动画名
            let animateName = function(){
                let animation = {
                    'animation': 'animationend',
                    'OAnimation': 'oAnimationEnd',
                    'MozAnimation': 'mozAnimationEnd',
                    'WebkitAnimation': 'webkitAnimationEnd'
                }
                let animateName = (function(el) {
                    for (let t in animation) {
                        if (el.style[t] !== undefined) {
                            return animation[t];
                        }
                    }
                })(document.createElement('div'));
                return animateName;
            }();
            //2、给ele绑定动画结束的回调
            let animateEndEventListener = function(sucHandle){
                //在每次transitionEnd的事件后执行该函数
                let handleAniEnd = function(e){
                    ele.removeEventListener(animateName,handleAniEnd);
                    sucHandle.call(this,e,ele);
                };
                ele.addEventListener(animateName,handleAniEnd,false);
            }
            animateName ? animateEndEventListener(sucHandle):errHandle(ele);
        }
        //转为二位数组
        ,toTwoArray:function(arr,num){
            let rows = [];
            num = num||7;
            arr = arr.concat();
            while(arr.length > 0) {
                rows.push(arr.splice(0, num));
            }
            return rows;
        }
        //小于10，添0补位
        ,addZero(num){
            return num < 10 ? '0'+num:num;
        }
        ,dateFormat:function(year,month,day,separate){
            separate = separate || '-';
            return year + separate + this.addZero(month) + separate + this.addZero(day);
        }
        ,getYMD:function(date){
            return {year:date.getFullYear(),month:date.getMonth()+1,day:date.getDate()}
        }
        ,times:function(num){
            let arr = [],i=0;
            while(num>0){
                num--;
                arr.push(++i);
            }
            return arr;
        }
        //获取（m+1）月一号的前一天是几号==>m月的最后一天
        ,getDays:function(y,m){
            let date = new Date(y,m,0);
            return date.getDate();
        }
        //获取某年某月第一天是周几,0->周日
        ,getWeek:function(y,m){
            return new Date(y,m-1,1).getDay();
        }
        //获取到上个月最后前n天
        ,getPreMonthDays:function(date,days){
            let num = []
                ,calNum = CheckCalendar.utils.getDays(date.getFullYear(),date.getMonth());
            for(let i=calNum-days+1; i<=calNum; i++){
                num.push(i);
            }
            return num;
        }
        //获取日期数据
        ,getCalData:function(date){
            let data = []
                ,week = CheckCalendar.utils.getWeek(date.getFullYear(),date.getMonth()+1)
                ,days = CheckCalendar.utils.getDays(date.getFullYear(),date.getMonth()+1)
                ,trs = Math.ceil((days+week)/7)
                ,fullDay = trs*7-week;
            //减去week天，就添加这些天
            Array.prototype.push.apply(data,CheckCalendar.utils.getPreMonthDays(date,week));
            Array.prototype.push.apply(data,CheckCalendar.utils.times(days));
            Array.prototype.push.apply(data,CheckCalendar.utils.times(fullDay-days));
            return data;
        }
        ,getCurDateStr:function(){
            return CheckCalendar.utils.dateFormat(curDate.getFullYear(),curDate.getMonth()+1,curDate.getDate())
        }
        ,getYMs:function(date,datesStr){
            let days = CheckCalendar.utils.getDays(date);
            date = CheckCalendar.utils.getYMD(date);
            let dateStr = date.year+"-"+CheckCalendar.utils.addZero(date.month)
                , reg = new RegExp(dateStr+'-[0-'+days+']');
            return datesStr.filter(function(date){
                return reg.test(date);
            })
        }
    };

    CheckCalendar.prototype = {
        constructor:CheckCalendar
        ,ready:function(){
            let flag = this.renderBefore();
            if(flag === false){return;}
            this.render();
            this.rendered();
        }
        ,renderBefore:function(){
            let flag = this.setting.events.renderBefore.call(this);
            if(flag === false){return flag;}
            !this.setting.scrollbar && $('html').css('overflow','hidden')
        }
        ,render:function(){
            this.renderCalBody(this.curDate);
            this.renderCheckBtn();
            this.setting.shade && this.addShade()
            !this.setting.isVisible && (this.setting.isVisible = true)
        }
        ,renderCalContent:function(calData,date){
            calData = CheckCalendar.utils.toTwoArray(calData,7);
            let html = ''
                ,year = date.getFullYear()
                ,month = date.getMonth()+1;
            for(let i=0; i<calData.length; i++){
                let rowData = calData[i];
                html+='<tr>'
                for(let j=0; j<rowData.length; j++){
                    let day = rowData[j]
                    if(i==0){
                        let minNum = Math.min.apply(null,rowData);
                        let index = rowData.indexOf(minNum);
                        if(j<index){
                            html+='<td><div><span class="hz-txt-gray">'+day+'</span></div></td>'
                            continue;
                        }
                    }
                    if(i==calData.length-1){
                        let maxNum = Math.max.apply(null,rowData);
                        let index = rowData.indexOf(maxNum);
                        if(j>index){
                            html+='<td><div><span class="hz-txt-gray">'+day+'</span></div></td>'
                            continue;
                        }
                    }
                    let dateStr = CheckCalendar.utils.dateFormat(year,month,day)
                    let isChecked = this.setting.checkTimes.indexOf(dateStr);
                    if(isChecked>-1 && dateStr == CheckCalendar.utils.getCurDateStr()){
                        html+='<td><div><span class="hz-checked hz-cur-day">'+day+'</span></div></td>';
                        continue;
                    }
                    if(isChecked>-1){
                        html+='<td><div><span class="hz-checked">'+day+'</span></div></td>';
                        continue;
                    }
                    if(dateStr == CheckCalendar.utils.getCurDateStr()){
                        html+='<td><div><span class="hz-cur-day">'+day+'</span></div></td>';
                        continue;
                    }
                    html+='<td><div><span>'+day+'</span></div></td>'
                }
                html+='</tr>'
            }
            return html;
        }
        ,renderCalBody(date){
            let $ele = $(this.ele);
            !$ele.hasClass('hz-calendar') && $ele.addClass('hz-calendar')
            let calData = this.calData = CheckCalendar.utils.getCalData(date);
            let html = '<div class="calendar-head">'
            html+='<div class="row-item">'
            html+='<div class="cur-date txt-center cursor-pointer">'
            html+='<i class="layui-icon layui-icon-triangle-l prev-btn"></i>'
            html+='<div class="layui-inline cur-date-container">'
            html+='<span class="cur-year">'+date.getFullYear()+'</span>年'
            html+='<span class="cur-month">'+CheckCalendar.utils.addZero(date.getMonth()+1)+'</span>月'
            html+='</div>'
            html+='<i class="layui-icon layui-icon-triangle-r next-btn"></i>'
            html+='</div>'
            html+='</div>'
            html+='<div class="row-item txt-center"><div class="layui-inline check-count">本月累计签到 <span>'+(CheckCalendar.utils.getYMs(date,this.setting.checkTimes).length||0)+'</span> 天</div></div>'
            html+='<div class="close-icon"><i class="layui-icon layui-icon-close"></i></div>'
            html+='</div>'
            html+='<div class="calendar-body">'
            html+='<table>'
            html+='<thead>'
            html+='<tr>'
            this.setting.calTags.forEach(function(tag,i){
                html+='<th>'+tag+'</th>'
            });
            html+='</tr>'
            html+='</thead>'
            html+='<tbody>'+this.renderCalContent(calData,date)+'</tbody>'
            html+='</table>'
            html+='</div>';
            if(!this.isRender){
                $ele.html(html).removeClass('layui-hide').addClass('bounce-in-top');
            }else{
                $ele.find('.calendar-head').remove();
                $ele.find('.calendar-body').remove();
                $('.check-btn').before(html)
            }
        }
        ,renderCheckBtn:function(){
            if(this.setting.checkTimes.indexOf(CheckCalendar.utils.getCurDateStr())>-1){
                return $(this.ele).append('<div class="check-btn"><button disabled class="layui-btn layui-btn-sm layui-btn-disabled">每日签到</button></div>')
            }else{
                return $(this.ele).append('<div class="check-btn"><button class="layui-btn layui-btn-sm">每日签到</button></div>')
            }
        }
        ,rendered:function(){
            //渲染结束
            this.isRender = true;
            this.events();
        }
        ,events:function(){
            let _self = this;
            $(this.ele).on('click','.prev-btn',function(){
                _self.eventList['prev'].call(_self,this);
            })
            .on('click','.next-btn',function(){
                _self.eventList['next'].call(_self,this);
            })
            .on('click','.close-icon',function(){
                _self.cancel();
            })
            .on('click','.check-btn button',function(){
                let flag = _self.setting.events.checkBefore.call(_self,this);
                if(flag === false){return;}
                _self.eventList['check'].call(_self,this);
            });
            $('body').on('click','.hz-check-calendar-shade',function(){
                _self.setting.shadeClose && _self.cancel();
            })
        }
        ,eventList:{
            'prev':function(el){
                let date = new Date(this.showDate)
                let flag = this.setting.events.toggleBefore.call(this,date,-1,this.renderCalByDate.bind(this,this.showDate,-1))
                if(flag === false){return;}
                this.renderCalByDate(this.showDate,-1);
            }
            ,'next':function(){
                let date = new Date(this.showDate)
                let flag = this.setting.events.toggleBefore.call(this,date,1,this.renderCalByDate.bind(this,this.showDate,1))
                if(flag === false){return;}
                this.renderCalByDate(this.showDate,1)
            }
            ,'check':function(el){
                // let date = CheckCalendar.utils.getYMD(this.curDate);
                // this.setting.checkTimes.push(CheckCalendar.utils.dateFormat(date.year,date.month,date.day));
                // this.renderCalBody(this.curDate)
                //$(el).attr('disabled',true).addClass('layui-btn-disabled')
            }
        }
        ,show:function(){
            this.setting.isVisible = true;
            !this.setting.scrollbar && $('html').css('overflow','hidden')
            if(!this.isRender){
                this.render(this.curDate)
            }else{
                this.setting.shade && this.addShade()
                $(this.ele).removeClass('layui-hide').addClass('bounce-in-top')
            }
        }
        ,cancel:function(){
            let _self = this;
            this.setting.shade && this.delShade()
            $(_self.ele).removeClass('bounce-in-top').addClass('bounce-out-top')
            CheckCalendar.utils.animationEnd(_self.ele,function(){
                $(this).addClass('layui-hide').removeClass('bounce-out-top')
            })
            !this.setting.scrollbar && $('html').removeAttr('style')
            this.setting.isVisible = false;
        }
        ,renderCalByDate:function(date,direct){
            direct = direct||1;
            this.showDate.setFullYear(this.showDate.getFullYear(),this.showDate.getMonth()+direct)
            this.renderCalBody(this.showDate);
        }
        ,addShade:function(){
            let $shade = ''
            $(".hz-check-calendar-shade").length == 0 && (
                $shade = $('<div class="hz-check-calendar-shade">')
                    ,$('body').append($shade)
                    ,$shade.fadeIn(800)
            )
        }
        ,delShade:function(){
            $(".hz-check-calendar-shade").fadeOut(800,function(){
                $(this).remove()
            });
        }
    }

    return CheckCalendar;
});